package com.robusta.app.auth.persistence;

import com.robusta.app.auth.model.UserModel;
import com.robusta.app.auth.model.UserSessionModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import static com.google.common.base.Preconditions.checkState;
import static com.robusta.app.auth.model.UserSessionModel.Status.ACTIVE;
import static com.robusta.app.auth.model.UserSessionModel.Status.INACTIVE;

@Repository
public class UserSessionRepositoryJpa implements UserSessionRepository {
    @PersistenceContext
    private EntityManager entityManager;
    private static final Logger LOGGER = LoggerFactory.getLogger(UserSessionRepositoryJpa.class);

    @Override
    public UserSessionModel createSessionForUserId(Long userId, String authToken) {
        UserModel loggedInUser = entityManager.find(UserModel.class, userId);
        checkState(loggedInUser != null, "Expected to find a user with id: %s, but " +
                "persistence did not find anything for this id. Cannot proceed to session creation", userId);
                LOGGER.debug("Creating a session with token: %s for user: %s", authToken, loggedInUser.getLoginName());
        UserSessionModel model = new UserSessionModel(authToken, loggedInUser);
        entityManager.persist(model);
        return model;
    }

    @Override
    public UserSessionModel lookupUserSessionByToken(String authToken) {
        // Join the User along with the session, since it will be invariably required. This would avoid an extra db call.
        return entityManager.createQuery("SELECT userSession FROM UserSessionModel userSession left join fetch userSession.loggedInUser " +
               "where userSession.token= :token and userSession.status = :status", UserSessionModel.class)
               .setParameter("token", authToken)
               .setParameter("status", ACTIVE)
               .getSingleResult();
    }

    @Override
    public int inactivateCurrentSessionsForUser(Long userId) {
        return entityManager.createQuery("UPDATE UserSessionModel set status = :inActiveStatus where loggedInUser.id = :id and status = :activeStatus")
                .setParameter("inActiveStatus", INACTIVE)
                .setParameter("activeStatus", ACTIVE)
                .setParameter("id", userId)
                .executeUpdate();
    }
}
